'''
Created on Nov 19, 2010

@author: dexen
'''

import sys
import traceback

import rpyc


from dexen.system.common.service import DexenAddr
from dexen.system.common.transact import S_BUSY, S_CRASHED, S_IDLE,\
SlaveRecvTransact, SlaveSendTransact

#===============================================================================
# Slave Proxy
#===============================================================================
class SlaveProxy(object):
    def __init__(self, slave_name, slave_addr, schema_meta):
        assert isinstance(slave_addr, DexenAddr)
        self.name = slave_name
        self.transact = None
        self.addr = slave_addr
        self.state = None
        self.sent_transact = None
        
        try:
            self.conn = slave_addr.get_conn()
            self.conn.root.setup_schema(schema_meta)
        except:
            self.state = S_CRASHED
            print sys.exc_info()
            print "------------------------------"
            traceback.print_tb(sys.exc_info()[2])
            print "SlaveProxy: I am in exception when connecting"
    
    def is_crashed(self):
        return self.state == S_CRASHED
    
    def is_idle(self):
        return self.state == S_IDLE

    def is_busy(self):
        return self.state == S_BUSY

    def execute(self, transact, master_state):
        assert isinstance(transact, SlaveSendTransact)
        transact.set_slave_name(self.name)
        self.sent_transact = transact
        if self.is_crashed(): return
        try:
            self.state = S_BUSY 
            self.conn.root.execute(transact, master_state)
        except:
            self.state = S_CRASHED

    def _handle_crash(self):
        sent_transact = self.sent_transact
        assert isinstance(sent_transact, SlaveSendTransact)
        transact = sent_transact.create_slave_recv_transact()
        assert isinstance(transact, SlaveRecvTransact)
        transact.slave_crashed()
        self.transact = transact
        
    def update(self):    
        if self.is_crashed():
            self._handle_crash()
            return
        try:
            transact = self.conn.root.get_output()
            transact = rpyc.classic.obtain(transact) # beware output can be none                
            if transact != None:
                """ 
                Note that the completed means either the script finished success
                fully or crashed
                The script crashed is different from slave crashed                  
                """
                print "In SlaveProxy:", transact
                self.state = S_IDLE
                assert isinstance(transact, SlaveRecvTransact)
                self.transact = transact     
        except:
            self.state = S_CRASHED
            self._handle_crash()
    
    def get_transact(self):
        return self.transact          

    def get_sent_transact(self):
        return self.sent_transact
